/*
 * ConcreteSplitViewer program for analazing splits.
 * Copyright (C) 2006-2007 Mytinski Leonid (Leonid.Mytinski@gmail.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 */ 

/*
 * StandardSplitViewer.java
 *
 * Created on 28 �?юнь 2006 г., 13:07
 */

package ru.concretesoft.concretesplitviewer;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Vector;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import ru.spb.ConcreteSoft.tipWindow.MouseMoveQueue;
import ru.spb.ConcreteSoft.tipWindow.TipWindow;


/**
 *
 * @author Mytinski Leonid
 * 
 * Panel for viewing splits in standatd way
 * Панель для отображения сплитов в стандартном виде
 */
public class StandardSplitViewer extends javax.swing.JPanel implements SplitViewer,ListDataListener,ListSelectionListener, MouseListener, MouseMotionListener{
    private AthleteListModel aModel;
    private int[] xCoord;
    private int otst=5;

    private TipWindow tipWindow;
    private TipThreadSplitViewer tipThread;
    private Vector<XCoordinatesListener> listeners;
    private GlassStandartSplitViewerPanel glassPane;
    private int editingCPNumber;
    private AthleteIcon editingAthlete;
    private int yLocationOfStartDrag;
   
    /**
     * Creates new form StandardSplitViewer
     */
    public StandardSplitViewer() {
        tipWindow = new TipWindow();
        initComponents();
        addMouseMotionListener(MouseMoveQueue.getInstance());
        addMouseListener(this);
        addMouseMotionListener(this);
        listeners = new Vector<XCoordinatesListener>();
        glassPane = new GlassStandartSplitViewerPanel();
    }


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {

        setLayout(new java.awt.GridBagLayout());

    }// </editor-fold>//GEN-END:initComponents
    @Override
    public void paint(Graphics g){
        Graphics2D g2 = (Graphics2D)g;
        Dimension d = getSize();
        g2.setPaint(Color.WHITE);
        g2.fillRect(0,0,d.width,d.height);
        FontMetrics fM = g2.getFontMetrics();

        otst = fM.stringWidth("-000:00")+5;
        int width = d.width-otst;
        int height = d.height;//-heightStr-2;
        AthleteIcon[] athletes = (AthleteIcon[])(aModel.getSelectedValues());
        int[] spl = aModel.getViewingSplits();
        Distance dist = aModel.getDistance();
        int size = athletes.length;
        

        
        if((spl!=null)&&(size>0)){
            
            // Calculating CP's x coordinates
            xCoord = new int[spl.length];
            if(dist!=null){
                int totDist = Tools.calculateTotalLength(dist, spl);
                int curDist=otst;
                for(int i=0;i<spl.length;i++){
                    xCoord[i]=curDist + (int)((dist.getLengthOfDist(spl[i])/(double)totDist)*width);
                    curDist = xCoord[i];
                }
            } else {
                int sizeLap = width/spl.length;
                for(int i=0;i<spl.length;i++)
                    xCoord[i] = sizeLap*(i+1);
            }
            
            // Draw vertical black line for each viewing CP
            g2.setPaint(Color.BLACK);
            for(int i=0;i<spl.length;i++){
                g2.drawLine(xCoord[i],0,xCoord[i],height);
            }
            
            // Calculate and draw horizontal lines with time 
            int yMax = athletes[size-1].getTotalTime().getTimeInSeconds();
            int hTime = fM.getHeight();
            double stepTime = 30.0;
            int nT =(int) (yMax/stepTime);
            while((height/nT)<(hTime+10)){
                stepTime*=2;
                nT = (int) (yMax/stepTime);
            }
            Time tmp = new Time(0,2);

            String s = tmp.getTimeString();
            g2.setPaint(Color.BLACK);
            g2.drawString(s,otst-fM.stringWidth(s),height-1);
            float dash1[] = {10.0f};
            BasicStroke dashed = new BasicStroke(1.0f, 
                                                  java.awt.BasicStroke.CAP_BUTT, 
                                                  java.awt.BasicStroke.JOIN_MITER, 
                                                  10.0f, dash1, 0.0f);
            g2.setStroke(dashed);
            for(int i=1;i<nT;i++){
                int timeCur = Math.abs((int)(stepTime*i));
                
                tmp.setTimeInSeconds(timeCur);
                s = tmp.getTimeString();
                int yH = height - (int)((stepTime*i / yMax)*height);
                g2.setPaint(Color.BLACK);
                g2.drawString(s,otst-fM.stringWidth(s),yH);
               
                g2.setPaint(Color.LIGHT_GRAY);
                g2.drawLine(otst,yH,otst + width,yH);
            }
            
   
            tmp.setTimeInSeconds((int)(stepTime*nT));
            s = tmp.getTimeString();
            
            g2.setPaint(Color.BLACK);
            g2.drawString(s,otst-fM.stringWidth(s),hTime+1);
            int yH = height - (int)((stepTime*nT / yMax)*height);
            g2.setPaint(Color.LIGHT_GRAY);
            g2.drawLine(otst,yH,otst + width,yH);
            
            // Draw charts
            g2.setStroke(new BasicStroke(1.0f));

            for(int j=0;j<size;j++){
                g2.setPaint(athletes[j].getColor());
                
                Athlete tmpA = athletes[j].getAthlete();

                int x = xCoord[0];
                int y = height - (int)((tmpA.getLap(spl[0]).getTimeInSeconds() / (double)yMax)*height);
                int totTime = tmpA.getLap(spl[0]).getTimeInSeconds();
                g2.drawLine(otst,height,x,y);
                for(int i=1;i<spl.length;i++){
                    int x1 = xCoord[i];
                    if (tmpA.getLap(spl[i]).getTimeInSeconds()==0) break;
                    totTime += tmpA.getLap(spl[i]).getTimeInSeconds();
                    int y1 = height - (int)(( totTime / (double)yMax)*height);
                    g2.drawLine(x,y,x1,y1);
                    x=x1;
                    y=y1;
                }
            }
        }else{
            xCoord=null;
        }
        
        // Notify listeners about changing of x coordinates
        for(XCoordinatesListener e: listeners){
            e.xCoordinatesChanged(this);
        }
    }

    @Override
    public String toString(){
        return java.util.ResourceBundle.getBundle("ru/concretesoft/concretesplitviewer/i18on").getString("Standart_View");
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables

    public void removeSplit(int x) {
        
        
        if(xCoord!=null){
            for(int i=0;i<xCoord.length;i++){
                if(x<xCoord[i]){
                    aModel.removeSplitsForN(aModel.getViewingSplits()[i]);
                    break;
                }
            }
        }
    }
    public void setModel(AthleteListModel aM){
        aModel = aM;
        aM.addListDataListener(this);
        aM.addListSelectionListener(this);
    }
    public AthleteListModel getModel(){
        return aModel;
    }
    public int getSplit(Point p){
        if(xCoord!=null){
            for(int i=0;i<xCoord.length; i++){
                if(p.getX()<xCoord[i]){
                    return aModel.getViewingSplits()[i];
                }else;
            }
        }else{
            return -1;
        }
        return -1;
    }


    public void intervalAdded(ListDataEvent e) {
        contentsChanged(e);
    }

    public void intervalRemoved(ListDataEvent e) {
        contentsChanged(e);
    }

    public void contentsChanged(ListDataEvent e) {
        repaint();
    }

    public void valueChanged(ListSelectionEvent e) {
        repaint();
    }

    public void mouseClicked(MouseEvent evt) {
        if((evt.getButton()==MouseEvent.BUTTON2)||(MouseEvent.getMouseModifiersText(evt.getModifiers()).equals("Shift+Button1"))){
            aModel.restoreAllSplits();
        }
        else if(evt.getButton()==MouseEvent.BUTTON1){
            
            removeSplit(evt.getX());
        }
    }

    public void mousePressed(MouseEvent e) {
        //Find near node
        int x = e.getX();
        int y = e.getY();
        for(int i = 0; i < xCoord.length; i++){
            System.out.println(x+" "+xCoord[i]);
            if(Math.abs(xCoord[i]-x) < 5){// 5 horizontal points on both sides
                editingCPNumber = i;//index(only from viewing) of control point which would be edited
                AthleteIcon[] selectedAthletes = (AthleteIcon[]) aModel.getSelectedValues();
                int yMax = selectedAthletes[selectedAthletes.length-1].getTotalTime().getTimeInSeconds();
                double scale = yMax / (double)getSize().height;
                for(int j = 0; j < selectedAthletes.length; j++){
                    int yA = 0;
                    for(int k=0;k<=editingCPNumber;k++){
                        yA += selectedAthletes[j].getAthlete().getLap(aModel.getViewingSplits()[k]).getTimeInSeconds();
                    }
                    yA = getSize().height - (int)(yA/scale);
                    System.out.println(y+" "+yA);
                    if(Math.abs(y-yA)<2){// 2 vertical points on both sides
                        yLocationOfStartDrag = yA;// Store y coordinate(of node) of start dragging
                        editingAthlete = selectedAthletes[j];// set editing athlete
                        // put all needed parameters to glass panel
                        glassPane.setAthlete(editingAthlete);
                        glassPane.setViewingSplits(aModel.getViewingSplits());
                        glassPane.setCPsNumber(editingCPNumber);
                        glassPane.setScale(scale);
                        glassPane.setXCoord(xCoord);
                        glassPane.setYMax(yMax);
                        glassPane.setOtst(otst);
                        glassPane.setLocationOnScreen(this.getLocationOnScreen());
                        glassPane.setVisible(true);
                        glassPane.setYLocation(y);
                        System.out.println(editingAthlete.getAthlete().getFamilyName());
                        break;
                    }
                }
                break;
            } else if(x < xCoord[i]){
                break;
            }
        }
    }

    public void mouseReleased(MouseEvent e) {
        glassPane.setVisible(false);
        glassPane.setAthlete(null);
        if(editingAthlete == null){
            return ;
        }
        AthleteIcon[] selectedAthletes = (AthleteIcon[]) aModel.getSelectedValues();
        int yMax = selectedAthletes[selectedAthletes.length-1].getTotalTime().getTimeInSeconds();
        double scale = yMax / (double)getSize().height;
        editingCPNumber = aModel.getViewingSplits()[editingCPNumber];
        Time oldTime = editingAthlete.getAthlete().getLap(editingCPNumber);
        int diff = e.getY()-yLocationOfStartDrag;
        int diffInSec = (int)(diff*scale);
        Time newTime = new Time(0, 2);
        newTime.setTimeInSeconds(oldTime.getTimeInSeconds()-diffInSec);
        editingAthlete.getAthlete().setTimeOnLap(newTime, editingCPNumber);
        editingAthlete = null;
        editingCPNumber = 0;
    }

    public void mouseEntered(MouseEvent e) {
        tipThread = new TipThreadSplitViewer(tipWindow, this);
        tipThread.start();
    }

    public void mouseExited(MouseEvent e) {
        tipThread.finish();
    }

    public int[] getXCoordinatesOfLaps() {
        return xCoord;
    }

    public void addXCoordinatesListener(XCoordinatesListener listener) {
        listeners.add(listener);
    }
    public void removeXCoordinatesListener(XCoordinatesListener listener) {
        listeners.remove(listener);
    }

    public GlassStandartSplitViewerPanel getGlassPane() {
        return glassPane;
    }

    public void mouseDragged(MouseEvent e) {
        if (editingAthlete == null){
            return ;
        }
        glassPane.setYLocation(e.getY());
    }

    public void mouseMoved(MouseEvent e) {
        
    }
    
}
